#include <iostream>
using namespace std;

#include <vector>
#include <algorithm>

namespace HQ
{
    template <typename T>
    class auto_ptr
    {
    public:
        // 已经废弃
        auto_ptr<T>(T* ptr = nullptr)
            : _ptr(ptr)
        {}

        auto_ptr<T>(const auto_ptr<T>& sp)
            : _ptr(sp._ptr)
        {
            sp._ptr = nullptr;
        }

        auto_ptr<T>& operator=(const auto_ptr<T>& sp)
        {
            if (this != &sp)
            {
                if (_ptr)
                {
                    delete _ptr;
                }
                _ptr = sp._ptr;
                sp._ptr = nullptr;
            }
            return *this;
        }

        ~auto_ptr()
        {
            if (_ptr)
            {
                delete _ptr;
            }
        }

        T& operator*()
        {
            return _ptr;
        }

        T* operator->()
        {
            return _ptr;
        }
    private:
        T* _ptr;
    };

    template <typename T>
    class unique_ptr
    {
    public:
        unique_ptr<T>(T* ptr = nullptr)
            : _ptr(ptr)
        {}

        ~unique_ptr<T>()
        {
            if (_ptr)
            {
                delete _ptr;
            }
        }

        T* operator->()
        {
            return _ptr;
        }

        T& operator*()
        {
            return *_ptr;
        }

        unique_ptr<T>(const unique_ptr<T>&) = delete;
        unique_ptr<T>& operator=(const unique_ptr<T>&) = delete;
    private:
        T* _ptr;
    };

    template <typename T>
    class shared_ptr
    {
    public:
        shared_ptr<T>(T* ptr = nullptr)
            : _ptr(ptr)
            , _pcount(new int(1))
        {}

        template <typename D>
        shared_ptr<T>(T* ptr, D del)
            : _ptr(ptr)
            , _pcount(new int(1))
            , _del(del)
        {}

        shared_ptr<T>(const shared_ptr<T>& sp)
            : _ptr(sp._ptr)
            , _pcount(sp._pcount)
        {
            ++(*_pcount);
        }

        void release()
        {
            if (--(*_pcount) == 0)
            {
                _del(_ptr);

                delete _pcount;
                _ptr = nullptr;
                _pcount = nullptr;
            }
        }

        shared_ptr<T>& operator=(const shared_ptr<T>& sp)
        {
            if (this != &sp)
            {
                release();

                _ptr = sp._ptr;
                _pcount = sp._pcount;
                ++(*_pcount);
            }
            return *this;
        }

        ~shared_ptr<T>()
        {
            release();
        }

        T* get() const 
        {
            return _ptr;
        }

        int use_count() const 
        {
            return *_pcount;
        }

        T* operator->()
        {
            return _ptr;
        }

        T& operator*()
        {
            return *_ptr;
        }       
    private:
        T* _ptr;
        int* _pcount;
        std::function<void(T* ptr)> _del = [](T* ptr){delete ptr;};
    };
}

int main()
{
    HQ::auto_ptr<int> ap(new int(1));
    HQ::unique_ptr<int> up(new int(1));
    HQ::shared_ptr<int> sp(new int(1));

    return 0;
}